package com.zkh.myutils.utils;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * 数组集合操作工具类
 * @author zkh
 */
public class ArrayUtils {
	
	/**
	 * 将多个数组组装成一个数组
	 * @param arrs 多个数组
	 */
	@SuppressWarnings("unchecked")
	public static <T> T[] combine(Class<T> cls, T[]... arrs){
		//创建泛型集合
		List<T> list = new ArrayList<T>();
		//将数组添加到泛型集合
		forEach(arrs, arr->Assert.doIfNotNull(arr, t->list.addAll(Arrays.asList(t))));
		//创建与集合等长的数组并赋值
		return map(getArray(cls, list.size()), (e,i)->list.get(i));
	}
	
	/**
	 * 创建一个指定长度的数组
	 * @param cls 数组类型
	 * @param length 数组长度
	 */
	@SuppressWarnings("unchecked")
	public static <T> T[] getArray(Class<T> cls, int length) {
		return (T[]) Array.newInstance(cls, length);
	}
	
	/**
	 * 创建一个指定长度的数组，并将值def填充每项元素中
	 * @param cls 数组类型
	 * @param length 数组长度
	 * @param def 默认值
	 */
	public static <T> T[] getArray(Class<T> cls, int length, T def) {
		return map(getArray(cls, length), v->def);
	}
	
	/**
	 * 自定义数组类型转换
	 * @param <T> 目标类型
	 * @param <K> 源类型
	 * @param origin 源数组
	 * @param cls 目标类型
	 * @param fun 自定义转换逻辑
	 * @return
	 */
	public static <T, K> T[] convertType(K[] origin, Class<T> cls, Function<K, T> fun) {
		//不为空，则执行
		return Assert.getIfNotNull(origin, arr->map(getArray(cls, arr.length), (e, i)->fun.apply(arr[i])));
	}
	
	/**
	 * 遍历数组
	 * @param array 待遍历的数组
	 */
	public static <T> void forEach(T[] array, BiConsumer<T, Integer> biConsumer) {
		//不为空，则遍历
		Assert.doIfNotNull(array, elems->{
			//遍历
			for(int i=0,len=elems.length;i<len;i++) {
				biConsumer.accept(elems[i], i);
			}
		});
	}
	
	/**
	 * 遍历数组
	 * @param array 待遍历的数组
	 */
	public static <T> void forEach(T[] array, Consumer<T> consumer) {
		forEach(array, (t, i)->consumer.accept(t));
	}
	
	/**
	 * 遍历并处理数组中的每一个元素值，返回原数组引用
	 * @param array 待遍历的数组
	 * @param biFunction 自定义处理值的逻辑
	 */
	public static <T> T[] map(T[] array, BiFunction<T, Integer, T> biFunction) {
		//遍历并返回原数组引用
		return Assert.getIfNotNull(array, elems->{
			//遍历
			for(int i=0,len=elems.length;i<len;i++) {
				elems[i] = biFunction.apply(elems[i], i);
			}
			//返回
			return elems;
		});
	}
	
	/**
	 * 遍历并处理数组中的每一个元素值，返回原数组引用
	 * @param array 待遍历的数组
	 * @param function 自定义处理值的逻辑
	 */
	public static <T> T[] map(T[] array, Function<T, T> function) {
		return map(array, (t, i)->function.apply(t));
	}
	
	/**
	 * 查找索引
	 * @param target 待查找的对象
	 * @param arrays 查找范围
	 */
	@SafeVarargs
	public static <T> int indexOf(T target, T... arrays) {
		//范围不为空
		if(arrays!=null) {
			//遍历
			for(int i=0; i<arrays.length; i++) {
				//相等，则返回索引
				if(Objects.equals(target, arrays[i])) {
					return i;
				}
			}
		}
		//未找到
		return -1;
	}
	
	/**
	 * 将Object转换为Object[]类型。前提是Object本身是数组，只是不确定具体是什么类型的数组
	 */
	public static Object[] getArray(Object arrObj) {
		//数组容器
		Object[] arr = new Object[Array.getLength(arrObj)];
		//赋值
		for(int i=0,len=arr.length;i<len;i++) {
			arr[i] = Array.get(arrObj, i);
		}
		//返回
		return arr;
	}
	
	/**
	 * 将数组转换成可操作的集合
	 */
	@SafeVarargs
	public static <T> List<T> asList(T ...a){
		return new ArrayList<T>(Arrays.asList(a));
	}
}
